--TEAM Vocabulary: Science and Health--
A 4am crack                  2016-01-04
---------------------------------------

Name: TEAM Vocabulary: Science and
  Health
Version: 1.0 (disk label says 040190,
  likely the release date, 1990-04-01)
Genre: educational
Year: 1990
Credits:
  designed by Jan Davidson, L. House,
    F. Schwartz, and J.M. Albanese
  written by Kevin R. Burley
Publisher: Davidson & Associates, Inc.
Media: 3.5-inch floppy (800K)
OS: ProDOS 1.4
Previous cracks: none
Similar cracks:
  #478 Word Attack Plus! Spanish (3.5")

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


Copy ][+ 9.1 ("COPY" > "DISK")
  read error on block $0308; copy loads
  ProDOS then quits to program selector

CFFA 3000 import
  read error on block 776 (= $0308);
  booting the disk image in an emulator
  exhibits the same behavior as the
  backup I made with Copy ][+ disk copy
  (boots ProDOS then quits via a "Quit"
  MLI call)

It's a very ProDOS-y way of saying
"f--- you."

The original disk boots without
complaint, so either this bad block is
part of a protection check, or it's
unrelated and I got incredibly lucky.

Next steps:

  1. Trace the startup program
  2. Find and disable the protection
     check
  3. Declare victory(*)

(*) Take a nap

                   ~

               Chapter 1
        In Which We Meditate On
       The Definition Of Success


[S7,D1=ProDOS hard drive]
[S5,D1=original disk]

]PR#7
]CAT,S5,D1

/WORD

 NAME           TYPE  BLOCKS  MODIFIED

 AFORTH          BIN      43  11-OCT-88
 WAP.SYSTEM      SYS       4  11-OCT-88
 TK.ABS          BIN      28  11-OCT-88
 PRODOS          SYS      32  11-OCT-88
 G13.OVL         TXT      25  11-OCT-88
 G4.OVL          TXT       7  11-OCT-88
 G5.OVL          TXT      13  11-OCT-88
 ED.OVL          TXT      22  11-OCT-88
 PRINT.OVL       TXT      11  11-OCT-88
 GAME.STR.OBJ    TXT      10  11-OCT-88
 ED.STR.OBJ      TXT       7  11-OCT-88
 PRINT.STR.OBJ   TXT       1  11-OCT-88
 IMAGE.OBJ       TXT      15  11-OCT-88
 CERT.PAK        TXT       7  29-JAN-90
 DESKTOP         $00       3   5-OCT-56
 ENTRY.PAK       TXT       6  26-JAN-90
 FOREIGN.FONT.3  BIN       7  11-OCT-88
 PRINTER.DATA    TXT       1  29-JAN-90
 PRINTER.DRIVERS TXT      12  11-OCT-88
 INTER.DRIVERS   TXT       5  11-OCT-88
 DUMP.HIRES.R    BIN       5  11-OCT-88
 DATA            DIR       1  25-APR-90
*STARTUP         BAS       3  11-OCT-88
*SI              BAS       4  11-OCT-88
*SU2C            BAS      39  11-OCT-88
*SU2E            BAS      34  11-OCT-88
*SU1.OBJ         BIN      31  11-OCT-88
*SU2.OBJ         BIN       9  11-OCT-88
*SU3.OBJ         BIN      62  11-OCT-88
*SU4.OBJ         VAR      18  11-OCT-88
*SU5.OBJ         BIN       1  11-OCT-88
*SU6.OBJ         VAR      15  11-OCT-88
*UTILITIES       SYS      21  11-OCT-88
 CONVERT         SYS       4  11-OCT-88
 MFORTH          BIN      52  11-OCT-88
 FINDER.DATA     $C9       3  22-APR-90
 MAIN.PAK        TXT      10   7-MAR-90

BLOCKS FREE:  772     BLOCKS USED:  828

ProDOS always loads the first .SYSTEM
file at $2000 and jumps to it.

]PREFIX /WORD
]BLOAD WAP.SYSTEM,A$2000,TSYS
]CALL -151

*2000L

2000-   20 D2 25    JSR   $25D2
2003-   4C 74 08    JMP   $0874

There's nothing loaded at $0874 yet, so
the subroutine at $25D2 must load
something from disk or copy something
from memory.

*25D2L

; straightforward memory relocation
25D2-   A2 00       LDX   #$00
25D4-   BD 03 20    LDA   $2003,X
25D7-   9D 01 08    STA   $0801,X
25DA-   BD 03 21    LDA   $2103,X
25DD-   9D 01 09    STA   $0901,X
25E0-   BD 03 22    LDA   $2203,X
25E3-   9D 01 0A    STA   $0A01,X
25E6-   BD 03 23    LDA   $2303,X
25E9-   9D 01 0B    STA   $0B01,X
25EC-   BD 03 24    LDA   $2403,X
25EF-   9D 01 0C    STA   $0C01,X
25F2-   BD 03 25    LDA   $2503,X
25F5-   E8          INX
25F6-   D0 DC       BNE   $25D4
25F8-   60          RTS

That's harmless enough. Let's run it.

*25D2G

*874L

0874-   20 C8 0A    JSR   $0AC8
0877-   F0 D9       BEQ   $0852

Down the rabbit hole we go.

*AC8L

; $BF30 is the last used slot and drive
; in "DSSS0000" format ("Beneath Apple
; ProDOS", p. 8-6)
0AC8-   AD 30 BF    LDA   $BF30
0ACB-   4A          LSR
0ACC-   4A          LSR
0ACD-   4A          LSR
0ACE-   4A          LSR
0ACF-   29 07       AND   #$07
0AD1-   09 C0       ORA   #$C0

; slot number munged into the high byte
; of the drive slot ROM, e.g. $C6
0AD3-   85 61       STA   $61
0AD5-   A9 00       LDA   #$00
0AD7-   85 60       STA   $60

; standard fingerprinting to identify
; the drive ROM
0AD9-   A0 01       LDY   #$01
0ADB-   B1 60       LDA   ($60),Y
0ADD-   C9 20       CMP   #$20
0ADF-   D0 22       BNE   $0B03
0AE1-   A0 03       LDY   #$03
0AE3-   B1 60       LDA   ($60),Y
0AE5-   D0 1C       BNE   $0B03
0AE7-   A0 05       LDY   #$05
0AE9-   B1 60       LDA   ($60),Y
0AEB-   C9 03       CMP   #$03
0AED-   D0 14       BNE   $0B03
0AEF-   A0 FF       LDY   #$FF
0AF1-   B1 60       LDA   ($60),Y
0AF3-   D0 0E       BNE   $0B03

; 5.25-inch floppy drive, so check
; block $110 (somewhere on track $22)
0AF5-   A9 10       LDA   #$10
0AF7-   8D CE 0D    STA   $0DCE
0AFA-   A9 01       LDA   #$01
0AFC-   8D CF 0D    STA   $0DCF
0AFF-   D0 0C       BNE   $0B0D
0B01-   F0 0A       BEQ   $0B0D

; 3.5-inch floppy drive, so check
; block $308 (the uncopyable block!)
0B03-   A9 08       LDA   #$08
0B05-   8D CE 0D    STA   $0DCE
0B08-   A9 03       LDA   #$03
0B0A-   8D CF 0D    STA   $0DCF

; set up other MLI parameters
0B0D-   AD 30 BF    LDA   $BF30
0B10-   8D CB 0D    STA   $0DCB
0B13-   A9 03       LDA   #$03
0B15-   8D CA 0D    STA   $0DCA
0B18-   A9 CA       LDA   #$CA
0B1A-   8D CC 0D    STA   $0DCC
0B1D-   A9 0B       LDA   #$0B
0B1F-   8D CD 0D    STA   $0DCD

; call MLI to read the specified block
; from disk (the $80 byte following the
; JSR is the READ_BLOCK command, and
; following that is the address of the
; MLI parameter table, $0DCA)
0B22-   20 00 BF    JSR   $BF00
0B25-  [80 CA 0D]

; if there was NOT a disk read error,
; then branch
0B28-   90 09       BCC   $0B33

; if there was any error other than an
; I/O error ($27), then branch
0B2A-   C9 27       CMP   #$27
0B2C-   D0 05       BNE   $0B33

; success path is here
0B2E-   A9 FF       LDA   #$FF
0B30-   85 FF       STA   $FF
0B32-   60          RTS

; failure path is here
0B33-   A9 00       LDA   #$00
0B35-   85 FF       STA   $FF
0B37-   60          RTS

This is definitely a form of copy
protection. (Fun fact: it appears to be
written so it can be re-used for 5.25-
and 3.5-inch floppies.) It relies on
one specific block or sector being
unreadable, and fails if it's actually
readable. Since my copy didn't
reproduce the badness of block $308,
the MLI read routine unexpectedly
succeeds, and the program knows it's
been copied.

Returning to the caller at $0874:

0874-   20 C8 0A    JSR   $0AC8
0877-   F0 D9       BEQ   $0852

*852L

; read and write main memory
0852-   8E 04 C0    STX   $C004
0855-   8E 02 C0    STX   $C002

; call the quit handler (command $65)
0858-   20 00 BF    JSR   $BF00
085B-  [65 5E 08]

...which explains the behavior I saw on
my non-working copy.

                   ~

               Chapter 2
           In Which We Test
       Our Definition of Success


Let's reproduce the success path. I'm
not sure if the side effect of setting
zero page $FF is relevant, but let's
assume it is.

*FF:FF N 879G

The program loads without complaint.

Out of curiosity, I reproduced this
state and tried it with $FF=0.

*FF:00 N 879G

It still loads without complaint.

Popping the stack all the way back to
$2003, I can change JMP $0874 to $0879
and bypass the entire thing.

[S5,D1=non-working copy]

[Block Warden]
  ["C"hange device -> S5,D1]
  ["F"ollow file]
    ["WAP.SYSTEM"]

Block $0032, offset $04 change 74 to 79

]PR#5
...works...

Quod erat liberandum.

---------------------------------------
A 4am crack                     No. 551
------------------EOF------------------
